package com.hmdp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.BooleanUtil;
import com.hmdp.dto.Result;
import com.hmdp.entity.Shop;
import com.hmdp.mapper.ShopMapper;
import com.hmdp.service.IShopService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisLock;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.hmdp.utils.RedisConstants.SHOP_CASH_KEY;
import static com.hmdp.utils.RedisConstants.SHOP_LOCK_KEY;


/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    private RedissonClient redissonClient;
    //有缓存穿透的风险
    public Result queryWithPassThrough(Long id) {
        //先到redis中查
        Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries(SHOP_CASH_KEY + id);
        if(!entries.isEmpty()){
            Shop shop = BeanUtil.mapToBean(entries, Shop.class, true, null);
            return Result.ok(shop);
        }
        //没有就到数据库里面查找，并添加缓存

        Shop shop = getById(id);
        if(shop==null){
            stringRedisTemplate.opsForHash().put(SHOP_CASH_KEY+id,"", "");
            return Result.fail("店铺不存在");
        }
        Map<String, Object> shopMap = BeanUtil.beanToMap(shop);
        stringRedisTemplate.opsForHash().putAll(SHOP_CASH_KEY+id, shopMap);
        return Result.ok(shop);
    }

    //用互斥锁方案
    @Override
    public Result queryShopById(Long id) {
        //先到redis中查
        Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries(SHOP_CASH_KEY + id);
        if(!entries.isEmpty()){
            Shop shop = BeanUtil.mapToBean(entries, Shop.class, true, null);
            return Result.ok(shop);
        }
        //没有就到数据库里面查找，并添加缓存
        //尝试获取锁
        String shopKey=SHOP_LOCK_KEY+id;
        Shop shop = null;
//        RedisLock redisLock=new RedisLock(stringRedisTemplate);
        RLock redisLock = redissonClient.getLock(shopKey);
        try {
            boolean flag = redisLock.tryLock();
            if(!flag){
                //休眠并且重试
                while(true) {
                    Thread.sleep(50);
                    entries = stringRedisTemplate.opsForHash().entries(SHOP_CASH_KEY + id);
                    if(!entries.isEmpty()){
                        shop = BeanUtil.mapToBean(entries, Shop.class, true, null);
                        return Result.ok(shop);
                    }
                }
            }
            //获取到了锁，再查一下redis里面有没有数据
            shop = getById(id);
            if(shop==null){
                stringRedisTemplate.opsForHash().put(SHOP_CASH_KEY+id,"", "");
                return Result.fail("店铺不存在");
            }
            Map<String, Object> shopMap = BeanUtil.beanToMap(shop);
//        shopMap.put("id",id.toString());
            stringRedisTemplate.opsForHash().putAll(SHOP_CASH_KEY+id, shopMap);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            //释放锁
            redisLock.unlock();
        }

        return Result.ok(shop);
    }
//    private boolean tryLock(String key){
//        //传过来的key都带有自己的店铺id，每个店铺都会有自己的锁
//        Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, SHOP_LOCK_KEY, 10, TimeUnit.MINUTES);
//        return Boolean.TRUE.equals(flag);
//    }
//    private void unLock(String key){
//        stringRedisTemplate.delete(key);
//    }
}
